package com.luo.demo.security.controller;

import com.luo.demo.sc.base.utils.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

import static org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId;
import static org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction.oauth2AuthorizedClient;


/**
 * REST服务 - Controller
 *
 * @author luohq
 * @date 2022-02-18
 */
@RestController
@Slf4j
public class RestSvcController {

    @GetMapping("/hello")
    public String hello(Authentication authentication) {
        log.info("hello Authentication: {}", JsonUtils.toJson(authentication));
        String reply = "Reply Hello, " + authentication.getName() + "!";
        log.info("cur reply: {}", reply);
        return reply;
    }


    /**
     *  获取认证用户信息
     *
     * @param authentication 认证用户信息（由SpringSecurity自动注入）
     * @return
     */
    @GetMapping("/authInfo")
    public Map<String, Object> authInfo(Authentication authentication) {
        log.info("get Authentication: class={}", authentication.getClass());
        log.info("get Authentication: {}", JsonUtils.toJson(authentication));
        Map<String, Object> resultMap = new HashMap<>(2);
        //转换OAuth2认证信息
        OAuth2AuthenticationToken oAuth2AuthenticationToken = (OAuth2AuthenticationToken) authentication;
        //提取用户信息
        DefaultOidcUser oidcUser = (DefaultOidcUser) oAuth2AuthenticationToken.getPrincipal();
        resultMap.put("idToken", oidcUser.getIdToken().getTokenValue());
        resultMap.put("oidcUserInfo", oidcUser.getUserInfo().getClaims());
        resultMap.put("oidc.claims", oidcUser.getClaims());
        return resultMap;
    }


    @Resource
    private WebClient webClient;

    @Value("${spring.security.oauth2.resourceserver.resource1:http://oauth2-resource1:8090/articles}")
    private String resource1Uri;
    @Value("${spring.security.oauth2.resourceserver.resource2:http://oauth2-resource1:8091/articles}")
    private String resource2Uri;
    @Value("${spring.security.oauth2.authserver.resource1:http://oauth2-server:9000/api/articles}")
    private String authServerResourceUri;


    private final String clientRegistrationId = "luo-oauth2-client1";
    //private final String clientRegistrationId = "rbac-oauth2-client1";


    /**
     * 获取资源文章
     *
     * @param authorizedClient 根据逻辑客户端ID自动注入客户端授权信息（包括客户端注册信息、用户名、AccessToken、RefreshToken）
     * @return 资源文章列表
     */
    @GetMapping(value = "/resource1/articles1")
    public String[] getResource1Articles1(
            @RegisteredOAuth2AuthorizedClient(clientRegistrationId) OAuth2AuthorizedClient authorizedClient) {
        return this.getArticles1(this.resource1Uri, authorizedClient);
        //log.info("get articles1 uri: {} by OAuth2AuthorizedClient", resource1Uri, JsonUtils.toJson(authorizedClient));
        //String[] articles = this.webClient
        //        .get()
        //        .uri(this.resource1Uri)
        //        //自动注入AccessToken为Bearer Token
        //        .attributes(oauth2AuthorizedClient(authorizedClient))
        //        .retrieve()
        //        .bodyToMono(String[].class)
        //        .block();
        //log.info("get articles1, result: {}", JsonUtils.toJson(articles));
        //return articles;
    }


    @GetMapping(value = "/resource1/articles2")
    public String[] getResource1Articles2() {
        return this.getArticles2(this.resource1Uri, clientRegistrationId);
    }

	@GetMapping(value = "/resource2/articles1")
	public String[] getResource2Articles1(@RegisteredOAuth2AuthorizedClient(clientRegistrationId) OAuth2AuthorizedClient authorizedClient) {
		return this.getArticles1(this.resource2Uri, authorizedClient);
	}


	@GetMapping(value = "/resource2/articles2")
	public String[] getResource2Articles2() {
		return this.getArticles2(this.resource2Uri, clientRegistrationId);
	}


    @GetMapping(value = "/authserver/articles1")
    public String[] getAuthserverArticles1() {
        return this.getArticles2(this.authServerResourceUri, clientRegistrationId);
    }


    @GetMapping(value = "/authserver/articles2")
    public String[] getArticles4() {
        return this.postArticles2(this.authServerResourceUri, clientRegistrationId);
    }

    private String[] getArticles1(String uri, OAuth2AuthorizedClient authorizedClient) {
        log.info("get articles1 uri: {} by OAuth2AuthorizedClient", uri, JsonUtils.toJson(authorizedClient));
        String[] articles = this.webClient
                .get()
                .uri(uri)
                .attributes(oauth2AuthorizedClient(authorizedClient))
                .retrieve()
                .bodyToMono(String[].class)
                .block();
        log.info("get articles1, result: {}", JsonUtils.toJson(articles));
        return articles;
    }

    private String[] getArticles2(String uri, String clientId) {
        log.info("get articles2 uri: {} by clientId: {}", uri, clientId);
        String[] articles = this.webClient
                .get()
                .uri(uri)
                .attributes(clientRegistrationId(clientId))
                .retrieve()
                .bodyToMono(String[].class)
                .block();
        log.info("get articles2, result: {}", JsonUtils.toJson(articles));
        return articles;
    }

    private String[] postArticles2(String uri, String clientRegistrationId) {
        log.info("post articles2 uri: {} by clientId: {}", uri, clientRegistrationId);
        String[] articles = this.webClient
                .post()
                .uri(uri)
                .attributes(clientRegistrationId(clientRegistrationId))
                .retrieve()
                .bodyToMono(String[].class)
                .block();
        log.info("post articles2, result: {}", JsonUtils.toJson(articles));
        return articles;
    }


}
